package com.hxk.security.config;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 *Security 配置类
 */
@EnableWebSecurity //开启Security
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 配置不需要认证的请求
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**","/js/**","/index.html","/img/**","/fonts/**","/favicon.ico","/verifyCode");
    }


    /**
     * 请求授权
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/","/index").permitAll() //首页所有人都能访问
                .antMatchers("/level/1/**").hasAnyRole("VIP1") //以level1开头的请求必须是VIP1角色才可以访问
                .antMatchers("/level/2/**").hasAnyRole("VIP2") //以level2开头的请求必须是VIP2角色才可以访问
                .antMatchers("/level/3/**").hasAnyRole("VIP3") //以level3开头的请求必须是VIP3角色才可以访问
                .anyRequest().authenticated()
                .and()
                .csrf().disable().httpBasic();//关闭csrf
//                .exceptionHandling()
//                .accessDeniedHandler((HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) ->{
//                    response.setContentType("application/json:charset=utf-8");
//                    PrintWriter out = response.getWriter();
//                    out.write("没有访问权限！请先登录");
//                    out.flush();
//                    out.close();
//                })//没有权限请求拦截如果是前后端分离项目可以使用该方法，封装JSON然后写回给前端
//                .authenticationEntryPoint(new AuthenticationEntryPoint() {//非法请求拦截
//                    @Override
//                    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
//                        response.setContentType("application/json:charset=utf-8");
//                        PrintWriter out = response.getWriter();
//                        out.write("登录成功"+authException.getMessage());
//                        out.flush();
//                        out.close();
//                    }
//                });//如果是前后端分离项目可以使用该方法，封装JSON然后写回给前端
        //没有权限，默认到登陆页，开启登录页面
        http.formLogin() //开启登录页面，Security默认获取帐号和密码的input name分别为：username，password，默认的登陆页面地址为/login
                .usernameParameter("name")//指定登陆页面的帐号对应获取input name
                .passwordParameter("pwd")//指定登陆页面的密码对应获取input name
                .loginPage("/toLogin")//指定登陆页面
                .loginProcessingUrl("/login");//如果登陆页面中的<form th:action="@{/login}" method="post">，action地址和上面loginPage("/toLogin")相同，则不需要配置该项，如果不同，必须配置该项，不然报404
//                .successHandler((HttpServletRequest request, HttpServletResponse response, Authentication authentication)->{
//                    response.setContentType("application/json:charset=utf-8");
//                    PrintWriter out = response.getWriter();
//                    out.write("登录成功");
//                    out.flush();
//                    out.close();
//                })//如果是前后端分离项目可以使用该方法，封装JSON然后写回给前端
//                .failureHandler((HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException)->{
//                    response.setContentType("application/json:charset=utf-8");
//                    PrintWriter out = response.getWriter();
//                    out.write("登录失败");
//                    out.flush();
//                    out.close();
//                });//如果是前后端分离项目可以使用该方法，封装JSON然后写回给前端
        http.logout()//开启注销功能
//                .logoutSuccessHandler((HttpServletRequest request, HttpServletResponse response,Authentication authentication) -> {
//                    response.setContentType("application/json:charset=utf-8");
//                    PrintWriter out = response.getWriter();
//                    out.write("注销成功");
//                    out.flush();
//                    out.close();
//                })//如果是前后端分离项目可以使用该方法，封装JSON然后写回给前端
                .logoutSuccessUrl("/");//注销成功后跳转到首页

        http.rememberMe()//开启记住我功能
                .rememberMeParameter("remember");//设置获取input name，Security默认为remember-me


    }

    /**
     * 导入自定义UserDetailsService
     */
    @Resource
    private UserDetailsService userDetailsService;

    /**
     * 用户认证
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //创建一个密码加密方式
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

        //实地项目使用数据库获取用户权限的方式
        auth.userDetailsService(userDetailsService)// 设置自定义的userDetailsService
                .passwordEncoder(passwordEncoder);

        //设置在系统内存中模拟用户
//        auth.inMemoryAuthentication() //在系统内存中模拟用
//                .passwordEncoder(passwordEncoder) //设置密码加密方式
//                .withUser("hxk") //设置一个用户
//                .password(passwordEncoder.encode("123456"))//设置用户密码
//                .roles("VIP1")//设置用户角色
//                .and()//追加配置
//                .withUser("root")
//                .password(passwordEncoder.encode("123456"))
//                .roles("VIP2", "VIP3")
//                .and()
//                .withUser("admin")
//                .password(passwordEncoder.encode("123456"))
//                .roles("VIP1","VIP2","VIP3");
    }
}
